package http

import (
	"crypto/tls"
	"encoding/json"
	"nextFlow/utils"
	"github.com/dop251/goja"
	"github.com/dop251/goja_nodejs/require"
	"github.com/dop251/goja_nodejs/util"
	"github.com/parnurzeal/gorequest"
	"strings"
)

const ModuleName = "node:http"

type H map[string]interface{}

type SuperAgent struct {
	runtime *goja.Runtime
	util    *goja.Object
}

func Require(runtime *goja.Runtime, module *goja.Object) {
	requireWithHttp()(runtime, module)
}

func RequireWithHttp() require.ModuleLoader {
	return requireWithHttp()
}

func requireWithHttp() require.ModuleLoader {
	return func(runtime *goja.Runtime, module *goja.Object) {
		c := &SuperAgent{
			runtime: runtime,
		}

		c.util = require.Require(runtime, util.ModuleName).(*goja.Object)

		o := module.Get("exports").(*goja.Object)
		o.Set("request", func(call goja.FunctionCall) goja.Value {

			// 判断参数
			if len(call.Arguments) == 0 {
				return nil
			}

			if options, ok := call.Argument(0).(*goja.Object); ok {

				var method string

				if options.Get("method") != nil {
					method = strings.ToUpper(options.Get("method").String())
				}

				url := ""

				if options.Get("url") != nil {
					url = options.Get("url").String()
				}

				req := gorequest.New().
					TLSClientConfig(&tls.Config{InsecureSkipVerify: true})

				if header, ok := options.Get("header").(*goja.Object); ok {
					headerKeys := header.Keys()
					for _, headerKey := range headerKeys {
						req = req.Set(headerKey, header.Get(headerKey).String())
					}
				}

				var data interface{}

				if options.Get("data") != nil {
					data = options.Get("data").Export()
				}

				if method == "POST" {
					req = req.Post(url).
						Set("X-Requested-With", "XMLHttpRequest").
						Send(data)
				} else {
					req = req.Get(url).Query(data)
				}

				resp, bodyBytes, error := req.End()

				if len(error) > 0 {

					if fail, ok := goja.AssertFunction(options.Get("fail")); ok {
						fail(call.This, c.runtime.ToValue(H{"errMsg": error}))
					}

				} else {

					jsonObject := make(map[string]interface{})
					json.Unmarshal([]byte(bodyBytes), &jsonObject)

					if success, ok := goja.AssertFunction(options.Get("success")); ok {
						success(call.This, c.runtime.ToValue(H{
							"data":       jsonObject, //  JSON_parse(bodyBytes),
							"statusCode": resp.StatusCode,
							"header":     resp.Header,
							"cookies":    resp.Header["Set-Cookie"],
						}))
					}

				}

				if complete, ok := goja.AssertFunction(options.Get("complete")); ok {
					complete(call.This)
				}

			}

			return nil
		})
	}
}

func Enable(runtime *goja.Runtime) {
	runtime.Set("http", require.Require(runtime, ModuleName))
}

func init() {
	require.RegisterNativeModule(ModuleName, Require)
	utils.Registry.Add(Enable)
}
